#include "http_client.h"
#include "../base/debug.h"
#include "../base/safe_format.h"

HttpClient::Factory* HttpClient::factory_ = NULL;

HttpClient::Factory& HttpClient::GetFactory()
{
	if (!factory_)
		factory_ = new Factory();

	return * factory_;
}

void HttpClient::DeleteFactory()
{
	delete factory_;
	factory_ = NULL;
}

HttpClient* CreateHttpClient()
{
	HttpClient* http_client = HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP);
	if (!http_client)
		http_client = HttpClient::GetFactory().CreateObject(HttpClient::WININET);

	return http_client;
}

CString HttpClient::BuildRequestHeader(const TCHAR* name, const TCHAR* value)
{
	ASSERT1(name && *name);
	ASSERT1(value && *value);

	CString header;
	SafeCStringFormat(&header, _T("%s: %s\r\n"), name, value);
	return header;
}

HttpClient::StatusCodeClass HttpClient::GetStatusCodeClass(int status_code)
{
	ASSERT1(!status_code || (HTTP_STATUS_FIRST <= status_code && status_code <= HTTP_STATUS_LAST));

	return static_cast<StatusCodeClass>(status_code / 100 * 100);
}

HRESULT HttpClient::QueryHeadersString(HINTERNET request_handle, 
									   uint32 info_level, 
									   const TCHAR* name, 
									   CString* value, 
									   DWORD* index)
{
	ASSERT1(value);

	DWORD num_bytes = 0;
	HRESULT hr = QueryHeaders(request_handle, info_level, 
		name, NULL, &num_bytes, index);
	if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
		return hr;

	CString val;
	hr = QueryHeaders(request_handle, info_level, 
		name, val.GetBuffer(num_bytes / sizeof(TCHAR)), &num_bytes, index);
	if (FAILED(hr))
		return hr;

	ASSERT1(num_bytes);
	val.ReleaseBufferSetLength(num_bytes / sizeof(TCHAR));
	*value = val;
	return S_OK;
}

HRESULT HttpClient::QueryHeadersInt(HINTERNET request_handle, 
									uint32 info_level, 
									const TCHAR* name, 
									int* value, 
									DWORD* index)
{
	ASSERT1(value);
	info_level |= WINHTTP_QUERY_FLAG_NUMBER;
	DWORD value_size = sizeof(*value);
	HRESULT hr = QueryHeaders(request_handle, info_level,
		name, value, &value_size, index);
	if (FAILED(hr)) 
		return hr;
	
	ASSERT1(value_size == sizeof(*value));
	return S_OK;
}

HRESULT HttpClient::QueryOptionString(HINTERNET handle, 
									  uint32 option, CString* value)
{
	ASSERT1(value);

	DWORD num_bytes = 0;
	HRESULT hr = QueryOption(handle, option, NULL, &num_bytes);
	DWORD last_error = ::GetLastError();
	if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) 
		return hr;
	
	ASSERT1(num_bytes);
	CString val;
	hr = QueryOption(handle, option, val.GetBuffer(num_bytes), &num_bytes);
	if (FAILED(hr)) 
		return hr;
	
	ASSERT1(num_bytes);
	val.ReleaseBufferSetLength(num_bytes/sizeof(TCHAR));
	*value = val;
	return S_OK;
}

HRESULT HttpClient::QueryOptionInt(HINTERNET handle,
								   uint32 option,
								   int* value)
{
	ASSERT1(value);
	DWORD val = 0;
	DWORD num_bytes = sizeof(val);
	HRESULT hr = QueryOption(handle, option, &val, &num_bytes);
	if (FAILED(hr)) 
		return hr;

	ASSERT1(num_bytes == sizeof(val));
	*value = val;
	return S_OK;
}

HRESULT HttpClient::SetOptionString(HINTERNET handle,
									uint32 option,
									const TCHAR* value)
{
	ASSERT1(value);

	const void* buffer = value;
	DWORD buffer_length = _tcslen(value) * sizeof(TCHAR);
	return SetOption(handle, option, buffer, buffer_length);
}

HRESULT HttpClient::SetOptionInt(HINTERNET handle, uint32 option, int value)
{
	DWORD val = value;
	return SetOption(handle, option, &val, sizeof(val));
}